home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / stealth.exe / VIRCHECK.PAS < prev    next >
Pascal/Delphi Source File  |  1992-02-10  |  11KB  |  457 lines

  1. {$I-}
  2. {
  3. vircheck.pas
  4. Stealth Bomber Version 2.2
  5.  
  6. Kevin Dean
  7. Fairview Mall P.O. Box 55074
  8. 1800 Sheppard Avenue East
  9. Willowdale, Ontario
  10. CANADA    M2J 5B9
  11. CompuServe ID: 76336,3114
  12.  
  13. February 10, 1992
  14.  
  15.     This is the interface to the anti-virus system and CRC checks in the
  16. Stealth Bomber package.
  17.  
  18.     This code is public domain.
  19. }
  20.  
  21.  
  22. unit VirCheck;
  23.  
  24.  
  25. interface
  26.  
  27.  
  28. uses
  29.   DOS, DOSMCB, AllocBuf;
  30.  
  31.  
  32. type
  33.   crc32_t =
  34.     longint;
  35.  
  36.   FileCRC =
  37.     record
  38.     case boolean of
  39.       false:
  40.     (
  41.     SearchStr : array [1 .. 8] of char;    { Used by Stealth Bomber package only. }
  42.     );
  43.  
  44.       true:
  45.     (
  46.     Polynomial : crc32_t;            { Polynomial for this file. }
  47.     CRC : crc32_t;                { Calculated CRC for this file. }
  48.     );
  49.     end;
  50.  
  51.  
  52. { Anti-virus validation return code. }
  53. const
  54.   StealthOK          = $0000;    { No virus found. }
  55.   StealthIntrErr     = $0001;    { Interrupts set beyond the program's code space. }
  56.   StealthDOSMemErr   = $0002;    { DOS memory inconsistent with BIOS memory. }
  57.   StealthDOSHijacked = $0004;    { DOS interrupt hijacked by JMP FAR or CALL FAR. }
  58.   StealthFileErr     = $0001;    { File not found or unable to open. }
  59.   StealthFileDateErr = $0002;    { File date/time stamp invalid. }
  60.   StealthFileSizeErr = $0004;    { File size inconsistent between directory and file open checks. }
  61.   StealthCRCBadPoly  = $0008;    { CRC polynomial is invalid. }
  62.   StealthNoMem       = $0010;    { No memory to perform CRC check. }
  63.   StealthCRCInvalid  = $0020;    { CRC is invalid. }
  64.  
  65.  
  66. function StealthSysCheck : word;
  67. function StealthFileCheck(FileName : PathStr; FCRC : FileCRC) : word;
  68.  
  69.  
  70. implementation
  71.  
  72.  
  73. type
  74.   dWordRec =
  75.     record
  76.     Lo, Hi : word
  77.     end;
  78.  
  79.   BytePtr =
  80.     ^byte;
  81.  
  82.   WordPtr =
  83.     ^word;
  84.  
  85.   PtrPtr =
  86.     ^pointer;
  87.  
  88.  
  89. {***}
  90. function BIOSMemory : word;
  91.  
  92. var
  93.   Regs : Registers;    { Registers in memory check call. }
  94.  
  95. begin
  96. Intr($12, Regs);
  97. BIOSMemory := Regs.AX;
  98. end;
  99.  
  100.  
  101. {***}
  102. { Determine true segment address of pointer and check for wrap around memory. }
  103. function PtrSeg(Ptr : pointer) : word;
  104.  
  105. var
  106.   PSeg : word;    { True segment of pointer. }
  107.  
  108. begin
  109. PSeg := Seg(Ptr^) + Ofs(Ptr^) shr 4;
  110.  
  111. if PSeg < Seg(Ptr^) then
  112.   { Pointer points beyond standard 1M memory. }
  113.   PSeg := $FFFF;
  114.  
  115. PtrSeg := PSeg;
  116. end;
  117.  
  118.  
  119. {***}
  120. { Validate interrupt; make sure not beyond code space and not hijacked. }
  121. function ValidateIntr(IntrNum : integer; MemLimit : word) : word;
  122.  
  123. var
  124.   Result : word;        { Result of tests. }
  125.   I : record
  126.       case boolean of
  127.     false:
  128.       (
  129.       IPtr : pointer;    { Interrupt pointer. }
  130.       );
  131.  
  132.     true:
  133.       (
  134.       CodePtr : BytePtr;    { Pointer to interrupt; treat as data. }
  135.       );
  136.       end;
  137.   ISeg : word;            { Adjusted segment of I.IPtr. }
  138.   Target : pointer;        { Target of hijacked interrupt. }
  139.   IntrMCB : MCBPtr;        { MCB of hijacked interrupt. }
  140.   TargetMCB : MCBPtr;        { MCB of target of hijacking. }
  141.  
  142. begin
  143. { Assume interrupt is valid. }
  144. Result := StealthOK;
  145.  
  146. { Get interrupt and adjusted segment. }
  147. GetIntVec(IntrNum, I.IPtr);
  148. ISeg := PtrSeg(I.IPtr);
  149.  
  150. { Interrupt pointer invalid if between PSP and memory limit. }
  151. if (ISeg >= PrefixSeg) and (ISeg < MemLimit) then
  152.   Result := Result or StealthIntrErr;
  153.  
  154. { Check beginning of interrupt code for suspicious instructions. }
  155. case I.CodePtr^ of
  156.   $EA,        { JMP FAR <addr>. }
  157.   $9A:        { CALL FAR <addr>. }
  158.     begin
  159.     Target := PtrPtr(longint(I.CodePtr) + 1)^;
  160.     Result := Result or StealthDOSHijacked;
  161.     end;
  162.  
  163.   $2E:        { CS segment prefix. }
  164.     case WordPtr(longint(I.CodePtr) + 1)^ of
  165.       $2EFF,    { JMP FAR CS:[addr]. }
  166.       $1EFF:    { CALL FAR CS:[addr]. }
  167.     begin
  168.     Target := PtrPtr(Ptr(Seg(I.CodePtr^), WordPtr(longint(I.CodePtr) + 3)^))^;
  169.     Result := Result or StealthDOSHijacked;
  170.     end;
  171.       end;
  172.   end;
  173.  
  174. if Result and StealthDOSHijacked <> 0 then
  175.   begin
  176.   { Determine MCB's that own the interrupt and the target of the redirection. }
  177.   IntrMCB := MCBOwner(I.CodePtr);
  178.   TargetMCB := MCBOwner(Target);
  179.  
  180.   { Redirection is valid if it falls within the same MCB or falls outside memory limit. }
  181.   if (IntrMCB = TargetMCB) or (PtrSeg(target) >= MemLimit) then
  182.     Result := Result and not StealthDOSHijacked;
  183.   end;
  184.  
  185. ValidateIntr := Result;
  186. end;
  187.  
  188.  
  189. {***}
  190. { Perform anti-virus system check. }
  191. function StealthSysCheck : word;
  192.  
  193. var
  194.   Result : word;    { Result of tests. }
  195.   MCB : MCBPtr;        { Memory control block pointer. }
  196.   BIOSMem : word;    { Memory in paragraphs according to BIOS. }
  197.   DOSMem : word;    { Memory in paragraphs according to DOS. }
  198.   MemLimit : word;    { Limit of useable memory. }
  199.  
  200. begin
  201. { Assume system passes all tests. }
  202. Result := StealthOK;
  203.  
  204. BIOSMem := BIOSMemory * 64;
  205.  
  206. { Find last memory control block. }
  207. MCB := GetMCB;
  208. while MCB^.ID <> $5A do
  209.   MCB := NextMCB(MCB);
  210.  
  211. DOSMem := Seg(MCB^) + MCB^.Size + 1;
  212.  
  213. { DOS memory extenders may show more memory than BIOS and some versions of DOS may differ by up to 1k from BIOS memory. }
  214. if BIOSMem > DOSMem + 64 then
  215.   Result := Result or StealthDOSMemErr;
  216.  
  217. { Assume BIOS memory goes at least to 640k limit (may have been modified by virus). }
  218. if BIOSMem < $A000 then
  219.   MemLimit := $A000
  220. else
  221.   MemLimit := BIOSMem;
  222. if MemLimit < DOSMem then
  223.   MemLimit := DOSMem;
  224.  
  225. { Swap vectors taken over by Turbo Pascal. }
  226. SwapVectors;
  227.  
  228. Result := Result or ValidateIntr($21, MemLimit);    { DOS function interrupt. }
  229. Result := Result or ValidateIntr($24, MemLimit);    { Critical error interrupt. }
  230. Result := Result or ValidateIntr($25, MemLimit);    { Absolute disk read interrupt. }
  231. Result := Result or ValidateIntr($26, MemLimit);    { Absolute disk write interrupt. }
  232. Result := Result or ValidateIntr($1C, MemLimit);    { User timer interrupt. }
  233. Result := Result or ValidateIntr($28, MemLimit);    { DOS OK interrupt. }
  234.  
  235. { Restore vectors required by Turbo Pascal. }
  236. SwapVectors;
  237.  
  238. StealthSysCheck := Result;
  239. end;
  240.  
  241.  
  242. {***}
  243. { Extract the low word of a dword. }
  244. function LowW(DWord : longint) : word;
  245.  
  246. begin
  247. LowW := DWordRec(DWord).Lo;
  248. end;
  249.  
  250.  
  251. {***}
  252. { Extract the high word of a dword. }
  253. function HiW(DWord : longint) : word;
  254.  
  255. begin
  256. HiW := DWordRec(DWord).Hi;
  257. end;
  258.  
  259.  
  260. {***}
  261. { Calculate the CRC of a file.  The file is assumed to be open and the buffer is assumed to be valid. }
  262. function CalcCRC(var F : file; Buffer : BytePtr; BufSize : word; Polynomial : crc32_t) : crc32_t;
  263.  
  264. var
  265.   Table : array [0 .. 255] of crc32_t;    { CRC table. }
  266.   I : word;                { Byte counter. }
  267.   HalfI : ^crc32_t;            { Pointer to CRC of I div 2. }
  268.   CRC : crc32_t;            { Current CRC. }
  269.   BufPtr : BytePtr;            { Pointer to walk through Buffer. }
  270.  
  271. begin
  272. { Generate a CRC lookup table for faster calculation. }
  273. I := 0;
  274. HalfI := @Table[0];
  275. Table[0] := 0;
  276. while I < 256 do
  277.   begin
  278.   if Hi(HiW(HalfI^)) and $80 <> $00 then
  279.     begin
  280.     Table[I + 1] := HalfI^ shl 1;
  281.     Table[I] := Table[I + 1] xor Polynomial;
  282.     end
  283.   else
  284.     begin
  285.     Table[I] := HalfI^ shl 1;
  286.     Table[I + 1] := Table[I] xor Polynomial;
  287.     end;
  288.  
  289.   Inc(I, 2);
  290.   Inc(longint(HalfI), sizeof(crc32_t));
  291.   end;
  292.  
  293. { Calculate CRC. }
  294. CRC := 0;
  295. BlockRead(F, Buffer^, BufSize, I);
  296. while I <> 0 do
  297.   begin
  298.   BufPtr := Buffer;
  299.   while I <> 0 do
  300.     begin
  301.     CRC := (CRC shl 8) xor Table[Hi(HiW(CRC)) xor BufPtr^];
  302.  
  303.     Dec(I);
  304.     Inc(longint(BufPtr));
  305.     end;
  306.  
  307.   BlockRead(F, Buffer^, BufSize, I);
  308.   end;
  309.  
  310. CalcCRC := CRC;
  311. end;
  312.  
  313.  
  314. {***}
  315. { Check file header consistency and calculate CRC of file. }
  316. function StealthFileCheck(FileName : PathStr; FCRC : FileCRC) : word;
  317.  
  318. var
  319.   Result : word;    { Result of tests. }
  320.  
  321.   FN : PathStr;        { Complete file name with path. }
  322.   Dir : DirStr;        { Directory of ParamStr(0). }
  323.   Name : NameStr;    { Name of ParamStr(0). }
  324.   Ext : ExtStr;        { Extension of ParamStr(0). }
  325.  
  326.   DirInfo : SearchRec;    { File directory information. }
  327.   TimeStamp : DateTime;    { Time stamp within DirInfo. }
  328.  
  329.   OldFileMode : byte;    { Old file open mode. }
  330.   F : file;        { File handle for FN. }
  331.  
  332.   Buffer : BytePtr;    { Buffer for file's data. }
  333.   BufSize : word;    { Buffer size. }
  334.  
  335. begin
  336. { Assume file passes all tests. }
  337. Result := StealthOK;
  338.  
  339. { If name contains drive or directory, use un